home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
C
/
Frameworks
/
Grant's CGI Framework 1.0b14
/
Util
/
CGI.c
next >
Wrap
Text File
|
1996-04-12
|
49KB
|
1,763 lines
/*****
*
* Grant's CGI Framework
* (Common Grant Interface :-)
* by Grant Neufeld
* http://arpp.carleton.ca/grant/mac/grantscgi/
*
* CGI.c
*
* Standard functions for cgi applications.
*
* You must call InitCGIUtil in your application startup.
* You must install CGIAEHandle as the event handler for the WWWΩsdoc apple event
* You must write the function:
* void CustomCGIProcess ( CGIHdl theCGIHdl )
* which is where you will, guess what, do your application specific processing
* of the cgi stuff.
*
* Do not call any functions begining with lower case 'cgi' - you can use any of the
* others - but read their comments first for details.
*
* watch the homepage for future upgrades
*
*
* Copyright ©1995,1996 by Grant Neufeld
*
* http://arpp.carleton.ca/grant/
* gneufeld@ccs.carleton.ca
* grant@acm.org
* grant@kagi.com
*
* This source may be freely used as long as the copyright notice is kept in the source.
* I ask that you let me know of any enhancements (read: bug fixes) to this code.
* I would also like copies of (or discounts on) anything you produce this with, please.
*
* See the License and Limited Warranty Agreement for all the legal stuff.
*
*****/
#include "MyConfiguration.h"
#if kCompileWithCGICode
#include <stdio.h>
#include <string.h>
#if __profile__ && __MWERKS__
#include <Profiler.h>
#endif
#include "compiler_stuff.h"
#include "globals.h"
#include "AEFunc.h"
#include "DebugUtil.h"
#include "LogUtil.h"
#include "MemoryUtil.h"
#include "ProcessUtil.h"
#include "Quit.h"
#include "StringUtil.h"
/* CGI.h processes differently for CGI.c, this is controlled by defining __CGISegment__ */
#define __CGISegment__ 1
#include "CGI.h"
#undef __CGISegment__
/*** CONSTANT DECLARATIONS ***/
#define kHTTPHeaderStrs 3000
#define kHTTPHeaderOK 1
#define kHTTPHeaderRedirect 2
#define kHTTPHeaderErr 3
#define kHTTPHeaderPush 4
/*** LOCAL VARIABLES ***/
#if kCompileWithThreadedAppleEvents
static AEEventHandlerUPP vCGIAEResumeCompleteUPP;
#endif
static char * vNULLString;
/*** LOCAL FUNCTION PROTOTYPES ***/
static void cgiDisposeHandle ( CGIHdl );
static OSErr cgiAESearchDocProcess ( CGIHdl );
static OSErr cgiAEComplete ( CGIHdl );
#if kCompileWithThreadedAppleEvents
pascal void * CGIAESearchDocProcessThread ( void * );
pascal OSErr CGIAEResumeComplete ( const AppleEvent *, AppleEvent *, long );
#endif
#if kCompileWithCGImethod
static OSErr cgiAEGetParamHTTPMethod ( const AppleEvent *, AEKeyword, HTTPMethod *, char *, long );
#endif
static void cgiPostProcess ( CGIHdl );
/*** FUNCTIONS ***/
/* This initialization function MUST be called in the startup sequence of your
application if you use any of the CGI functions (including the AppleEvent) */
OSErr
InitCGIUtil ( void )
{
OSErr theErr;
AEEventHandlerUPP theUPP;
/* initialize the null string to consist of one character '\0' */
vNULLString = (char *) MemoryNewPtr ( 1, &theErr );
if ( vNULLString != NULL )
{
vNULLString[0] = nil;
}
else
{
/* IMPORTANT: we failed initialization
if we couldn't allocate a one byte string! */
if ( theErr == noErr )
{
/* make sure there's an error value */
theErr = memFullErr;
}
return theErr;
}
GetIndString ( gHTTPHeaderOK, kHTTPHeaderStrs, kHTTPHeaderOK );
if ( gHTTPHeaderOK[nil] != nil )
{
P2CStr ( gHTTPHeaderOK );
gHTTPHeaderOKSize = strlen ( (char *)gHTTPHeaderOK );
}
GetIndString ( gHTTPHeaderRedirect, kHTTPHeaderStrs, kHTTPHeaderRedirect );
if ( gHTTPHeaderRedirect[nil] != nil )
{
P2CStr ( gHTTPHeaderRedirect );
gHTTPHeaderRedirectSize = strlen ( (char *)gHTTPHeaderRedirect );
}
GetIndString ( gHTTPHeaderErr, kHTTPHeaderStrs, kHTTPHeaderErr );
if ( gHTTPHeaderErr[nil] != nil )
{
P2CStr ( gHTTPHeaderErr );
gHTTPHeaderErrSize = strlen ( (char *)gHTTPHeaderErr );
}
#if kCompileWithCGISendPartial
GetIndString ( gHTTPHeaderPush, kHTTPHeaderStrs, kHTTPHeaderPush );
if ( gHTTPHeaderPush[nil] != nil )
{
P2CStr ( gHTTPHeaderPush );
gHTTPHeaderPushSize = strlen ( (char *)gHTTPHeaderPush );
}
#endif
/* it's okay to 'lose track' of theUPP since we never want to get rid of it
until the application quits - at which point it will automatically be
disposed of, anyway. */
theUPP = NewAEEventHandlerProc ( CGIAESearchDoc );
theErr = AEInstallEventHandler ( kAEClassCGI, kAEIDSearchDoc, theUPP, 0L, false );
#if kCompileWithThreadedAppleEvents
vCGIAEResumeCompleteUPP = NewAEEventHandlerProc ( CGIAEResumeComplete );
#endif
return theErr;
} /* InitCGIUtil */
/** FORM FIELDS **/
#pragma mark -
#if kCompileWithCGIFormHandling
/* The separator '&' separates individual fields.
The delimiter '=' delimits the name and value in a field.
For example: "Field 1=some stuff&Another Field=more stuff&Last Field=no stuff"
Means that there are 3 fields with names "Field 1", "Another Field" and "Last Field"
The function returns an array of field records with the last containing null values.
You generally shouldn't call this function outside this file.
Use it at your own risk. */
/* ••• I should add error reporting */
p_export
CGIFormField *
CGIFormFieldsFromArgs ( char *theString, long *count, short *outErr )
{
CGIFormField * theFields;
long totalStrSize;
long totalFields;
long nameSize;
long valueSize;
long currentField;
char * theStringPtr;
char * fieldSeparator;
char * fieldDelimiter;
my_assert ( theString != NULL, "\pCGIFormArgs: nil string" );
theFields = NULL;
/* don't return number of fields until function is successful */
*count = nil;
totalStrSize = strlen ( theString );
/* the total number of fields is the number of separator characters + 1 */
totalFields = StringCountChar ( theString, kCGIFormFieldSeparator ) + 1;
if ( totalFields == 1 )
{
/* the case where there were no separator characters is special,
test for a field delimiter to confirm that the string passed does
indeed contain field information */
fieldDelimiter = StringChar ( theString, kCGIFormFieldDelimiter );
if ( fieldDelimiter == NULL )
{
/* string does not contain field data */
*outErr = 1; /* • might need better error here */
goto Exit_Fail;
}
}
theFields = (CGIFormField *) MemoryNewPtr ( ((totalFields + 1) * sizeof(CGIFormField)), outErr );
if ( theFields == NULL )
{
/* memory didn't allocate */
goto Exit_Fail;
}
/* set the name and value of the last field in the array to nil */
(theFields[totalFields]).name = NULL;
(theFields[totalFields]).value = NULL;
theStringPtr = theString;
for ( currentField = nil; currentField < totalFields; currentField++ )
{
/* set the name and value of the current field in the array to nil.
this is to handle errors. */
(theFields[currentField]).name = NULL;
(theFields[currentField]).value = NULL;
fieldDelimiter = StringChar ( theStringPtr, kCGIFormFieldDelimiter );
fieldSeparator = StringChar ( theStringPtr, kCGIFormFieldSeparator );
/* if there is a field delimiter, and it is before any field separator */
if ( (fieldDelimiter != NULL) && ((fieldSeparator > fieldDelimiter) ||
(fieldSeparator == NULL)) )
{
/* field name */
/* the size of the name string is the difference between the begining
of the field and the position of the field delimiter */
nameSize = fieldDelimiter - theStringPtr;
/* allocate the name string */
(theFields[currentField]).name = (char *) MemoryNewPtr ( nameSize + 1, outErr );
if ( (theFields[currentField]).name == NULL )
{
/* memory didn't allocate */
(theFields[currentField]).value = NULL;
goto Exit_Fail;
}
/* copy the field name */
BlockMove ( theStringPtr, (theFields[currentField]).name, nameSize );
/* null terminate the end of the name string */
((theFields[currentField]).name)[nameSize] = nil;
/* convert the url encoded text to a normal string */
CGIDecodeURLChars ( (theFields[currentField]).name );
/* field value */
if ( fieldSeparator != NULL )
{
valueSize = fieldSeparator - (fieldDelimiter + 1);
}
else
{
valueSize = strlen ( fieldDelimiter + 1 );
}
(theFields[currentField]).value = (char *) MemoryNewPtr ( (valueSize + 1), outErr );
if ( (theFields[currentField]).value == NULL )
{
/* memory didn't allocate */
DisposePtr ( (theFields[currentField]).name );
(theFields[currentField]).name = NULL;
goto Exit_Fail;
}
BlockMove ( fieldDelimiter + 1, (theFields[currentField]).value, valueSize );
((theFields[currentField]).value)[valueSize] = nil;
CGIDecodeURLChars ( (theFields[currentField]).value );
theStringPtr = fieldSeparator + 1;
}
else
{
/* invalid data encountered */
*outErr = 2; /* •• need better error value */
goto Exit_Fail;
}
}
/* assign the return parameters values */
*count = totalFields;
*outErr = noErr;
return theFields;
Exit_Fail:
if ( theFields != NULL )
{
/* release allocated memory */
CGIFormFieldsDispose ( theFields );
}
return NULL;
} /* CGIFormFieldsFromArgs */
/* Returns a pointer to the first form field record, in the given fieldArray,
that's name matches the supplied field name.
[modified for 1.0b4 - use CGIHdl as parameter instead of CGIFormField] */
p_export
CGIFormField *
CGIFormFieldsFindRecord ( CGIHdl theCGIHdl, const char *fieldName )
{
CGIFormField *fieldArray;
long currentField;
short stringDifference;
my_assert ( theCGIHdl != NULL, "\pCGIFormFieldsFindRecord: theCGIHdl is NULL" );
my_assert ( fieldName != NULL, "\pCGIFormFieldsFindRecord: fieldName is NULL" );
fieldArray = (*theCGIHdl)->formFields;
if ( (*theCGIHdl)->formFields == NULL )
{
return NULL;
}
/* look til we find something or we hit the end */
for ( currentField = nil; (fieldArray[currentField]).name != NULL; currentField++ )
{
stringDifference = strcmp ( (fieldArray[currentField]).name, fieldName );
if ( stringDifference == nil )
{
/* found a match, so we're done */
return &(fieldArray[currentField]);
}
}
/* didn't find a match */
return NULL;
} /* CGIFormFieldsFindRecord */
/* Returns a pointer to the string containing the value from the field specified
by 'fieldName'. Returns a pointer to a null string ("") if the field is not
found. The pointer points directly into the form fields array in theCGIHdl.
IMPORTANT: Whatever you do - do not attempt to deallocate the string returned
by this function!!! */
p_export
const char *
CGIFormFieldsFindValue ( CGIHdl theCGIHdl, const char *fieldName )
{
CGIFormField * theField;
my_assert ( theCGIHdl != NULL, "\pCGIFormFieldsFindValue: theCGIHdl is NULL" );
my_assert ( fieldName != NULL, "\pCGIFormFieldsFindValue: fieldName is NULL" );
theField = CGIFormFieldsFindRecord ( theCGIHdl, fieldName );
if ( (theField == NULL) || (theField->value == NULL) )
{
return vNULLString;
}
else
{
return theField->value;
}
} /* CGIFormFieldsFindValue */
/* Deallocate memory for theFields array.
You generally shouldn't call this function outside this file.
Use it at your own risk. */
void
CGIFormFieldsDispose ( CGIFormField *theFields )
{
long offset;
my_assert ( theFields != NULL, "\pCGIFormFieldsDispose: null field array pointer" );
offset = nil;
do
{
if ( (theFields[offset]).name != NULL )
{
/* if there's a name string, deallocate its memory */
DisposePtr ( (Ptr)((theFields[offset]).name) );
if ( (theFields[offset]).value != NULL )
{
/* if there's a value string, deallocate its memory */
DisposePtr ( (Ptr)((theFields[offset]).value) );
}
}
offset++;
} while ( (theFields[offset]).name != NULL );
DisposePtr ( (Ptr)theFields );
} /* CGIFormFieldsDispose */
#endif /* kCompileWithCGIFormHandling */
/** ACTION SUPPORT **/
#pragma mark -
#if kCompileWithCGIActionSupport
/* Returns true if the action parameter is either CGI or ACGI.
Returns false if it is some other action. */
p_export
Boolean
CGIActionIsCGIorACGI ( CGIHdl theCGIHdl )
{
int stringDifference;
my_assert ( theCGIHdl != NULL, "\pCGIActionIsCGIorACGI: theCGIHdl is NULL" );
/* is the action "CGI"? */
stringDifference = strcmp ( (*theCGIHdl)->action, kCGIActionNameCGI );
if ( stringDifference == nil )
{
return true;
}
/* is the action "ACGI"? */
stringDifference = strcmp ( (*theCGIHdl)->action, kCGIActionNameACGI );
if ( stringDifference == nil )
{
return true;
}
/* didn't find a match */
return false;
} /* CGIActionIsCGIorACGI */
#endif /* kCompileWithCGIActionSupport */
/** CHARACTER CODING **/
#pragma mark -
/* replaces instances of percent signs (%) followed by an ASCII char value
with the actual character.
This function modifies theString parameter! */
p_export
void
CGIDecodeURLChars ( char *theString )
{
UInt32 read;
UInt32 write;
unsigned char theChar;
unsigned char highOrder;
unsigned char lowOrder;
Boolean isValid;
my_assert ( theString != NULL, "\pCGIDecodeURLChars: NULL string" );
read = nil;
write = nil;
while ( theString[read] != nil )
{
switch ( theString[read] )
{
case '%':
/* a percent symbol begins a hex char block (%## where ## is the hex value) */
isValid = true;
/* determine high order hex character */
if ( (theString[read+1] >= 'A') && (theString[read+1] <= 'F') )
{
/* uppercase A-F convert to 10-15 */
highOrder = theString[read+1] - 'A' + 10;
}
else if ( (theString[read+1] >= 'a') && (theString[read+1] <= 'f') )
{
/* lowercase a-f convert to 10-15 */
highOrder = theString[read+1] - 'a' + 10;
}
else if ( (theString[read+1] >= '0') && (theString[read+1] <= '9') )
{
/* character digits 0-9 convert to decimal 0-9 */
highOrder = theString[read+1] - '0';
}
else
{
/* Illegal character! Can't convert from hex */
isValid = false;
}
/* Multiply high order hex digit by 16 */
highOrder *= 16;
/* determine low order hex character */
if ( (theString[read+2] >= 'A') && (theString[read+2] <= 'F') )
{
/* uppercase A-F convert to 10-15 */
lowOrder = (theString[read+2] - 'A' + 10);
}
else if ( (theString[read+2] >= 'a') && (theString[read+2] <= 'f') )
{
/* lowercase a-f convert to 10-15 */
lowOrder = (theString[read+2] - 'a' + 10);
}
else if ( (theString[read+2] >= '0') && (theString[read+2] <= '9') )
{
/* character digits 0-9 convert to decimal 0-9 */
lowOrder = (theString[read+2] - '0');
}
else
{
/* Illegal character! Can't convert from hex */
isValid = false;
}
theChar = highOrder + lowOrder;
if ( isValid )
{
isValid = (theChar >= 0) && (theChar < 256);
}
if ( isValid )
{
/* if theChar is valid, write it out */
if ( theChar == 10 )
{
/* don't write newline */
write--;
}
else
{
theString[write] = theChar;
}
/* Increment read past the two digits of the hex code */
read += 2;
}
else
{
/* invalid hex character code, just write out the percent symbol */
theString[write] = theString[read];
}
break;
case '+':
/* Plus symbols convert to space */
theString[write] = ' ';
break;
case 10:
/* ignore line feeds, we only need carriage returns (13) */
write--;
break;
default:
/* write out the character */
theString[write] = theString[read];
break;
}
read++;
write++;
}
/* terminate the string */
theString[write] = '\0';
} /* CGIDecodeURLChars */
/* • UPDATE 1996-03-10 •
%hex encode all non-alphanumeric characters. IE. '~' (126) becomes '%7E'
theString parameter is not modified.
Will return NULL if unable to allocate memory for the encoded string.
outErr will not be set if it is a NULL ptr. */
p_export
char *
CGIEncodeURLChars ( const char *theString, OSErr *outErr )
{
char * theResult; /* new string containing the encoded form of theString */
long strSize; /* size of the source string */
Boolean charNeedsToBeHex; /* char needs to be encoded as hex */
const char * stringLoc; /* current location in theString */
char * resultLoc; /* current location in theResult string */
my_assert ( theString != NULL, "\p: theString is NULL" );
/* loop through the string finding out how big our final string will need to be.
Add two extra bytes for every 'special' character. */
strSize = nil;
for ( stringLoc = theString; *stringLoc != nil; stringLoc++ )
{
charNeedsToBeHex = CGICharWillHex ( *stringLoc );
if ( charNeedsToBeHex )
{
/* the character at strOffset is alpha-numeric */
strSize++;
}
else
{
/* the character at strOffset is special (not alpha-numeric) */
strSize += 3;
}
}
/* allocate space for the new encoded string */
theResult = (char *) MemoryNewPtr ( (strSize + 1), outErr );
if ( theResult != NULL )
{
/* encode theString into the new encoded string (theResult).
loop through the characters of the old string,
copying the alpha-numeric chars to the new string,
but copying in %XX encoded form when non-alpha-numeric. */
for ( stringLoc = theString, resultLoc = theResult; *stringLoc != nil; stringLoc++, resultLoc++ )
{
charNeedsToBeHex = CGICharWillHex ( *stringLoc );
if ( charNeedsToBeHex )
{
/* if the character is alphanumeric just copy it */
*resultLoc = *stringLoc;
}
else
{
/* if the character is not alphanumeric, hex encode it */
CGICharToHex ( *stringLoc, resultLoc );
/* add the extra two characters for hex encoding to the result offset */
resultLoc += 2;
}
}
/* terminate the string after the last character written */
*resultLoc = nil;
}
return theResult;
} /* CGIEncodeURLChars */
/* returns true if theChar will be converted to hex when encoding as an URL string */
p_export
Boolean
CGICharWillHex ( unsigned char theChar )
{
return (
((theChar >= 'a') && (theChar <= 'z')) || /* 0x60 - 0x7A; a-z */
((theChar >= '?') && (theChar <= 'Z')) || /* 0x3F - 0x5A; ? @ A-Z */
((theChar >= '-') && (theChar <= ':')) || /* 0x2D - 0x3A; - . / 0-9 : */
((theChar >= '\"') && (theChar <= '$')) || /* 0x22 - 0x24; " # $ */
(theChar == '&') || (theChar == '\'') || /* 0x26 0x27; & ' */
(theChar == '=') ); /* 0x3D; = */
} /* CGICharWillHex */
/* Converts theChar to percent-hex encoding for URLs, and writes that to theString.
This assumes that theString is at least 4 bytes long (to have enough room to
write the hex encoded text). */
p_export
void
CGICharToHex ( unsigned char theChar, char *theString )
{
unsigned char chrChunk;
/* start off with a percent symbol to indicate a hex character code */
theString[0] = '%';
/* mask to get the high 4 bits, then shift them into the lower 4 bits */
chrChunk = (theChar & 0xF0) >> 4;
if ( chrChunk > 9 )
{
/* chrChunk is a value between A and F in hex */
theString[1] = (chrChunk - 10) + 'A';
}
else
{
/* chrChunk is a value between 0 and 9 in hex */
theString[1] = chrChunk + '0';
}
/* mask to get the low 4 bits */
chrChunk = theChar & 0x0F;
if ( chrChunk > 9 )
{
/* chrChunk is a value between A and F in hex */
theString[2] = (chrChunk - 10) + 'A';
}
else
{
/* chrChunk is a value between 0 and 9 in hex */
theString[2] = chrChunk + '0';
}
} /* CGICharToHex */
/* convert a '/' delimited path to a ':' delimited one, and make sure there's
one ':' at the start if the path includes folders.
This function may modify ioPathString.
ioPathString MUST have an extra byte after its terminating null byte. */
p_export
void
CGIPathToMacPath ( char *ioPathString )
{
char * theWorkString;
char * theSlashOffset;
/* we start with a directory marker, so we won't need to add one. */
if ( (ioPathString[0] == '/') || (ioPathString[0] == ':') )
{
StringConvertCharToChar ( ioPathString, '/', ':' );
}
else
{
/* check if there are any slashes */
theSlashOffset = strchr ( ioPathString, '/' );
if ( theSlashOffset == NULL )
{
/* there are no slashes, so nothing no change is needed. */
}
else
{
/* find the terminating null byte at the end of the string */
theWorkString = strchr ( ioPathString, '\0' );
while ( theWorkString >= ioPathString )
{
/* the char following the current one is written as a colon if
this one is a slash, or has this char written to it */
theWorkString[1] = (theWorkString[0] == '/')? ':' : theWorkString[0];
theWorkString--;
}
/* make sure there is a leading colon for the path */
ioPathString[0] = ':';
}
}
} /* CGIPathToMacPath */
/** Memory Allocation Cleanup **/
#pragma mark -
/* */
static void
cgiDisposeHandle ( CGIHdl theCGIHdl )
{
my_assert ( theCGIHdl != NULL, "\pcgiDisposeHandle: theCGIHdl is NULL" );
my_assert ( *theCGIHdl != NULL, "\pcgiDisposeHandle: *theCGIHdl is NULL" );
/* the following is a bunch of statements checking if a parameter has been
allocated and disposing of it if it has */
#if kCompileWithCGIpath_args
if ( (*theCGIHdl)->path_args != NULL )
{
DisposePtr ( (Ptr)((*theCGIHdl)->path_args) );
}
#endif
#if kCompileWithCGIhttp_search_args
if ( (*theCGIHdl)->http_search_args != NULL )
{
DisposePtr ( (Ptr)((*theCGIHdl)->http_search_args) );
}
#endif
#if kCompileWithCGIpost_args
if ( (*theCGIHdl)->post_args != NULL )
{
DisposePtr ( (Ptr)((*theCGIHdl)->post_args) );
}
#endif
#if kCompileWithCGIscript_name
if ( (*theCGIHdl)->script_name != NULL )
{
DisposePtr ( (Ptr)((*theCGIHdl)->script_name) );
}
#endif
#if kCompileWithCGIreferer
if ( (*theCGIHdl)->referer != NULL )
{
DisposePtr ( (Ptr)((*theCGIHdl)->referer) );
}
#endif
#if kCompileWithCGIActionSupport
if ( (*theCGIHdl)->action_path != NULL )
{
DisposePtr ( (Ptr)((*theCGIHdl)->action_path) );
}
#endif
#if kCompileWithCGIfull_request
if ( (*theCGIHdl)->full_request != NULL )
{
DisposePtr ( (Ptr)((*theCGIHdl)->full_request) );
}
#endif
#if kCompileWithCGIFormHandling
if ( (*theCGIHdl)->formFields != NULL )
{
CGIFormFieldsDispose ( (*theCGIHdl)->formFields );
}
#endif
if ( (*theCGIHdl)->responseData != NULL )
{
#if kCompileWithCGIResponseDataAsHandle
DisposeHandle ( (*theCGIHdl)->responseData );
#else
DisposePtr ( (Ptr)((*theCGIHdl)->responseData) );
#endif
}
DisposeHandle ( (Handle)theCGIHdl );
} /* cgiDisposeHandle */
/** APPLE EVENT SUPPORT **/
#pragma mark -
/* AppleEvent Handler for the CGI WWWΩ-sdoc event */
pascal OSErr
CGIAESearchDoc ( AppleEvent *theAppleEvent, AppleEvent *theReply, long Reference )
{
OSErr theErr;
CGIHdl theCGIHdl;
#if kCompileWithThreadedAppleEvents
ThreadID theThread;
#endif
#if kCompileWithDebugLogging
char tempStr[16];
#endif
/* we're handling a CGI event, so we're more busy now */
ProcessIsMoreBusy ();
/* reset 'quit on idle time' timer */
ResetQuitIdleTimer();
#if kCompileWithDebugLogging
LogStringP ( "\p==================\rCGI Event Recieved\rTICKS: " );
sprintf ( tempStr, "%d", TickCount() );
LogStringBreak ( tempStr );
LogStringBreakP ( "\p------------------" );
#endif
/* Allocate the CGIHdl data structure - zeroing out its contents. */
theCGIHdl = (CGIHdl) MemoryNewHandleClear ( sizeof(CGIrecord), &theErr );
if ( theCGIHdl == NULL )
{
/* memory didn't allocate - can't process cgi */
return theErr;
}
/* store references to the apple event and reply records */
(*theCGIHdl)->appleEvent = *theAppleEvent;
(*theCGIHdl)->replyEvent = *theReply;
// MoveHHi ( (Handle)theCGIHdl );
#if kCompileWithThreadedAppleEvents
#if kCompileWithThreadsOptional
if ( gHasThreadMgr )
{
#endif
/* It is necessary to suspend the AppleEvent in order to thread its
processing because of some real weirdness with AEProcessAppleEvent
not being "reentrant." This means you can't be processing multiple
Apple Events at the same time, so they have to be 'suspended' if
you want to deal with more than one (IE. multi-threaded processing). */
theErr = AESuspendTheCurrentEvent ( theAppleEvent );
if ( theErr == noErr)
{
(*theCGIHdl)->suspended = true;
/* AppleEvent has been suspended, so we can spawn a thread for processing. */
theErr = ThreadNewThreadFromPool ( CGIAESearchDocProcessThread,
theCGIHdl, (void**)NULL, &theThread );
}
#if kCompileWithThreadsOptional
}
#endif
#endif /* kCompileWithThreadedAppleEvents */
#if kCompileWithThreadedAppleEvents
#if kCompileWithThreadsOptional
if ( !gHasThreadMgr || (theErr != noErr) )
#else
if ( theErr != noErr )
#endif
{
#endif
/* if threading isn't available, or the attempt to thread failed,
or the attempt to suspend the AppleEvent failed,
process the Apple Event without threading. */
theErr = cgiAESearchDocProcess ( theCGIHdl );
#if kCompileWithThreadedAppleEvents
}
else
{
/* we suspended the AE, and spawned the thread, now let's start it. */
//••• YieldToThread ( theThread );
}
#endif
return theErr;
} /* CGIAESearchDoc */
/* Entry point for cgi handler thread. */
#if kCompileWithThreadedAppleEvents
pascal void *
CGIAESearchDocProcessThread ( void *threadParam )
{
OSErr theErr;
ThreadID currentThread;
my_assert ( threadParam != NULL,
"\pCGIAESearchDocProcessThread: the CGI handle (threadParam) is NULL" );
/* The threadParam is used to pass the CGIHdl. */
theErr = cgiAESearchDocProcess ( (CGIHdl)threadParam );
/* Find the ID of current thread and use DisposeThread to dispose of it so
that my custom thread termination procedure will be used to recycle
this thread's allocation for the thread pool. */
GetCurrentThread ( ¤tThread );
DisposeThread ( currentThread, (void *)theErr, true );
/* This line below is actually irrelevant, since the DisposeThread call above
will result in the immediate termination of this thread.
I keep it in because a return result is needed for the compiler not to
issue a warning (and I have the "treat all warnings as errors" flag set
in my compiler, like every programmer should). */
return (void *)theErr;
} /* CGIAESearchDocProcessThread */
#endif
/* Process the CGI WWWΩ-sdoc event.
theCGIHdl must be valid (non-nil) and unlocked.
Responsible for ensuring that cgiAEComplete is called so CGIDisposeHandle
will be called. */
static OSErr
cgiAESearchDocProcess ( CGIHdl theCGIHdl )
{
OSErr theErr;
Ptr tempBuffer;
AppleEvent theAppleEvent;
/* the 'fieldError' variable is only used if forms with auto-processing are on,
the method parameter is used, and one or both of the http_search_args and
post_args are used */
#if kCompileWithCGIFormHandling && kCompileWithCGIFormAutoProcess && kCompileWithCGImethod && (kCompileWithCGIhttp_search_args || kCompileWithCGIpost_args)
short fieldError;
#endif
my_assert ( theCGIHdl != NULL, "\pcgiAESearchDocProcess: theCGIHdl is NULL" );
// my_assert ( (*theCGIHdl)->appleEvent != NULL, "\pcgiAESearchDocProcess: theAppleEvent is nil" );
#if __profile__ && __MWERKS__
gProfileOn = !( ProfilerInit( collectDetailed, bestTimeBase, 20, 5 ) );
#endif
/* reset 'quit on idle time' timer */
ResetQuitIdleTimer();
tempBuffer = MemoryNewPtr ( kCGIParamMaxSize, &theErr );
if ( tempBuffer == NULL )
{
goto Exit_Complete;
}
my_assert ( (HGetState((Handle)theCGIHdl) & kMemoryHandleLockedFlag) == nil,
"\pcgiAESearchDocProcess: theCGIHdl is already locked!" );
HLockHi ( (Handle)theCGIHdl );
/* copy the AppleEvent record into a local variable for faster access. */
theAppleEvent = (*theCGIHdl)->appleEvent;
/* the following section is where the parameters are pulled from the CGI
Apple Event and allocated in the CGI Handle */
/* '----' - direct parameter:
path_args - arguments to the URL after a $ */
#if kCompileWithCGIpath_args
theErr = AEGetParamString ( &theAppleEvent, '----', &((*theCGIHdl)->path_args),
(char *)tempBuffer, kCGIParamMaxSize );
#if kCompileWithCGIAutoDecode
if ( theErr == noErr )
{
CGIDecodeURLChars ( (*theCGIHdl)->path_args );
}
#endif
#endif /* kCompileWithCGIpath_args */
/* 'kfor' - search arguments:
http_search_args - arguments to the URL after a ? */
#if kCompileWithCGIhttp_search_args
theErr = AEGetParamString ( &theAppleEvent, kCGIhttp_search_args,
&((*theCGIHdl)->http_search_args), (char *)tempBuffer, kCGIParamMaxSize );
/* leave decoding to after parsing of form fields */
#endif
/* 'user' - user name:
username - authenticated user name */
#if kCompileWithCGIusername
theErr = AEGetParamStringNoAlloc ( &theAppleEvent, kCGIusername,
(*theCGIHdl)->username, kCGIMaxusername );
#endif
/* 'pass' - password:
password - authenticated password */
#if kCompileWithCGIpassword
theErr = AEGetParamStringNoAlloc ( &theAppleEvent, kCGIpassword,
(*theCGIHdl)->password, kCGIMaxpassword );
#endif
/* 'frmu' - from user:
from_user - non-standard. e-mail address of remote user */
#if kCompileWithCGIfrom_user
theErr = AEGetParamStringNoAlloc ( &theAppleEvent, kCGIfrom_user,
(*theCGIHdl)->from_user, kCGIMaxfrom_user );
#endif
/* 'addr' - client address:
client_address - IP address or domain name of remote client's host */
#if kCompileWithCGIclient_address
theErr = AEGetParamStringNoAlloc ( &theAppleEvent, kCGIclient_address,
(*theCGIHdl)->client_address, kCGIMaxclient_address );
#endif
/* 'post' - post arguments:
post_args - */
#if kCompileWithCGIpost_args
theErr = AEGetParamString ( &theAppleEvent, kCGIpost_args,
&((*theCGIHdl)->post_args), (char *)tempBuffer, kCGIParamMaxSize );
/* leave decoding to after form parsing */
#endif
/* 'meth' - HTTP method:
method - GET, POST, etc. Used to tell if post_args are valid */
#if kCompileWithCGImethod
theErr = cgiAEGetParamHTTPMethod ( &theAppleEvent, kCGImethod,
&((*theCGIHdl)->method), (char *)tempBuffer, kCGIParamMaxSize );
#endif
/* 'svnm' - server name:
server_name - name or IP address of this server */
#if kCompileWithCGIserver_name
theErr = AEGetParamStringNoAlloc ( &theAppleEvent, kCGIserver_name,
(*theCGIHdl)->server_name, kCGIMaxserver_name );
#endif
/* 'svpt' - server port:
server_port - TCP/IP port number being used by this server */
#if kCompileWithCGIserver_port
theErr = AEGetParamShort ( &theAppleEvent, kCGIserver_port,
&((*theCGIHdl)->server_port), (char *)tempBuffer, kCGIParamMaxSize );
#endif
/* 'scnm' - script name:
script_name - URL name of this script */
#if kCompileWithCGIscript_name
theErr = AEGetParamString ( &theAppleEvent, kCGIscript_name,
&((*theCGIHdl)->script_name), (char *)tempBuffer, kCGIParamMaxSize );
#if kCompileWithCGIAutoDecode
if ( theErr == noErr )
{
CGIDecodeURLChars ( (*theCGIHdl)->script_name );
}
#endif
#endif
/* 'ctyp' - content type:
content_type - MIME content type of post_args */
#if kCompileWithCGIcontent_type
theErr = AEGetParamStringNoAlloc ( &theAppleEvent, kCGIcontent_type,
(*theCGIHdl)->content_type, kCGIMaxcontent_type );
#endif
/* 'refr' - referer:
referer - the URL of the page referencing this document */
#if kCompileWithCGIreferer
theErr = AEGetParamString ( &theAppleEvent, kCGIreferer,
&((*theCGIHdl)->referer), (char *)tempBuffer, kCGIParamMaxSize );
#endif
/* 'Agnt' - user agent:
user_agent - the name and version of the WWW client software being used */
#if kCompileWithCGIuser_agent
theErr = AEGetParamStringNoAlloc ( &theAppleEvent, kCGIuser_agent,
(*theCGIHdl)->user_agent, kCGIMaxuser_agent );
#endif
/* 'Kact' - action name:
action - the name of the action (CGI or ACGI if not a user defined action) */
#if kCompileWithCGIActionSupport
theErr = AEGetParamStringNoAlloc ( &theAppleEvent, kCGIaction,
(*theCGIHdl)->action, kCGIMaxaction );
#endif
/* 'Kapt' - action path:
action_path - path to the action application */
#if kCompileWithCGIActionSupport
theErr = AEGetParamString ( &theAppleEvent, kCGIaction_path,
&((*theCGIHdl)->action_path), (char *)tempBuffer, kCGIParamMaxSize );
#endif
/* 'Kcip' - client IP address:
client_ip - the IP address of the client */
#if kCompileWithCGIclient_ip
theErr = AEGetParamStringNoAlloc ( &theAppleEvent, kCGIclient_ip,
(*theCGIHdl)->client_ip, kCGIMaxclient_ip );
#endif
/* 'Kfrq' - full request:
full_request - the full text of the request */
#if kCompileWithCGIfull_request
theErr = AEGetParamString ( &theAppleEvent, kCGIfull_request,
&((*theCGIHdl)->full_request), (char *)tempBuffer, kCGIParamMaxSize );
#endif
/* 'Kcid' - connection ID:
connection - the ID of the server's connection with a client */
#if kCompileWithCGISendPartial
theErr = AEGetParamLong ( &theAppleEvent, kCGIconnection, &((*theCGIHdl)->connection) );
#endif
/* don't need the buffer any more */
DisposePtr ( tempBuffer );
//•don't need to check for required parameters because Chuck Shotton says that all
//parameters are to be optional.
// /* check that all required parameters were retreived */
// theErr = AEFuncGotRequiredParams ( &theAppleEvent );
#if kCompileWithCGIFormHandling && kCompileWithCGIFormAutoProcess && kCompileWithCGImethod
/* separate the form fields into an array */
switch ( (*theCGIHdl)->method )
{
#if kCompileWithCGIhttp_search_args
case HTTP_get :
if ( (*theCGIHdl)->http_search_args != NULL )
{
(*theCGIHdl)->formFields = CGIFormFieldsFromArgs (
(*theCGIHdl)->http_search_args, &((*theCGIHdl)->totalFields),
&fieldError );
}
break;
#endif
#if kCompileWithCGIpost_args
case HTTP_post :
if ( (*theCGIHdl)->post_args != NULL )
{
(*theCGIHdl)->formFields = CGIFormFieldsFromArgs (
(*theCGIHdl)->post_args, &((*theCGIHdl)->totalFields), &fieldError );
}
break;
#endif
}
#endif /* kCompileWithCGIFormHandling && kCompileWithCGIFormAutoProcess && kCompileWithCGImethod */
/* now that the possible need to use them for form fields is over, we can
decode the search args */
#if kCompileWithCGIAutoDecode && kCompileWithCGIhttp_search_args
if ( (*theCGIHdl)->http_search_args != NULL )
{
CGIDecodeURLChars ( (*theCGIHdl)->http_search_args );
}
#endif
HUnlock ( (Handle)theCGIHdl );
#if kCompileWithDebugLogging
CGILogData ( theCGIHdl );
#endif
/* this is where the application specific cgi handling comes into play
the function "CustomCGIProcess" must be provided by the user of this source code */
CustomCGIProcess ( theCGIHdl );
Exit_Complete:
#if __profile__ && __MWERKS__
if ( gProfileOn )
{
ProfilerDump ( "\p" kProfileNameStr "-" kProcessorString ".prof" );
ProfilerTerm ();
}
#endif
#if kCompileWithThreadedAppleEvents
if ( (*theCGIHdl)->suspended )
{
/* We're in a suspended AppleEvent, so we'll need to resume the
AppleEvent to have it complete and return the reply properly. */
theErr = AEResumeTheCurrentEvent ( &theAppleEvent,
&((*theCGIHdl)->replyEvent), vCGIAEResumeCompleteUPP, (long)theCGIHdl );
}
else
{
#endif
/* We weren't suspended, but still need to take care of the AppleEvent
reply record. */
theErr = cgiAEComplete ( theCGIHdl );
#if kCompileWithThreadedAppleEvents
}
#endif
/* reset 'quit on idle time' timer */
ResetQuitIdleTimer();
return theErr;
} /* cgiAESearchDocProcess */
/* Call the event completion function (cgiAEComplete) when resuming
suspended AppleEvents. theReference must be a CGIHdl.
The result returned from this function will be used as the result of the AppleEvent. */
#if kCompileWithThreadedAppleEvents
pascal OSErr
CGIAEResumeComplete ( const AppleEvent *theAppleEvent, AppleEvent *theReply, long theReference )
{
OSErr theErr;
my_assert ( theReference != nil,
"\pCGIAEResumeComplete: the CGI handle (theReference) is nil" );
theErr = cgiAEComplete ( (CGIHdl)theReference );
return theErr;
} /* CGIAEResumeComplete */
#endif
/* Complete the CGI AppleEvent. theCGIHdl must be valid. */
static OSErr
cgiAEComplete ( CGIHdl theCGIHdl )
{
OSErr theErr;
#if kCompileWithDebugLogging
char tempStr[16];
#endif
my_assert ( theCGIHdl != NULL, "\pcgiAEComplete: theCGIHdl is NULL" );
my_assert ( (HGetState((Handle)theCGIHdl) & kMemoryHandleLockedFlag) == nil,
"\pcgiAEComplete: theCGIHdl is already locked!" );
HLock ( (Handle)theCGIHdl );
if ( (*theCGIHdl)->responseData != NULL )
{
#if kCompileWithCGIResponseDataAsHandle
my_assert ( (HGetState((Handle)((*theCGIHdl)->responseData)) & kMemoryHandleLockedFlag) == nil,
"\pcgiAEComplete: (*theCGIHdl)->responseData is already locked!" );
HLock ( (*theCGIHdl)->responseData );
#endif
/* If the user's "CustomCGIProcess" function set the responseData properly,
return it. */
theErr = AEPutParamPtr ( &((*theCGIHdl)->replyEvent), keyDirectObject, typeChar,
#if kCompileWithCGIResponseDataAsHandle
*((*theCGIHdl)->responseData),
#else
(Ptr)((*theCGIHdl)->responseData),
#endif
(*theCGIHdl)->responseSize );
#if kCompileWithCGIResponseDataAsHandle
HUnlock ( (*theCGIHdl)->responseData );
#endif
}
else
{
/* if the user's "CustomCGIProcess" failed to set the responseData properly,
return an error header. */
theErr = AEPutParamPtr ( &((*theCGIHdl)->replyEvent), keyDirectObject, typeChar,
(Ptr)gHTTPHeaderErr, gHTTPHeaderErrSize );
}
HUnlock ( (Handle)theCGIHdl );
/* give time, then cgiPostProcess */
ProcessGiveTime ( nil );
cgiPostProcess ( theCGIHdl );
#if kCompileWithDebugLogging
CGILogData ( theCGIHdl );
#endif
/* deallocate memory */
cgiDisposeHandle ( theCGIHdl );
#if kCompileWithDebugLogging
LogStringP ( "\p___________________\rCGI Event Completed\rTICKS: " );
sprintf ( tempStr, "%d", TickCount() );
LogStringBreak ( tempStr );
LogStringBreakP ( "\p===================" );
#endif
/* we're done this CGI event, so we're less busy now */
ProcessIsLessBusy ();
return theErr;
} /* cgiAEComplete */
/* */
static void
cgiPostProcess ( CGIHdl theCGIHdl )
{
CustomCGIPostProcess ( theCGIHdl );
} /* cgiPostProcess */
#if kCompileWithCGImethod
#pragma segment AppleEvents
/* private function to get an HTTPMethod from an AppleEvent parameter */
static OSErr
cgiAEGetParamHTTPMethod ( const AppleEvent *theAppleEvent, AEKeyword theAEKeyword, HTTPMethod *theMethod, char *tempBuffer, long bufferSize )
{
OSErr theErr;
DescType actualType;
Size actualSize;
int stringDiff;
my_assert ( theMethod != NULL, "\pcgiAEGetParamHTTPMethod: theMethod ptr is NULL" );
my_assert ( theAppleEvent != NULL, "\pcgiAEGetParamHTTPMethod: theAppleEvent ptr is NULL" );
my_assert ( tempBuffer != NULL, "\pcgiAEGetParamHTTPMethod: tempBuffer ptr is NULL" );
theErr = AEGetParamPtr ( theAppleEvent, theAEKeyword, typeChar,
&actualType, (Ptr)tempBuffer, bufferSize, &actualSize );
if ( theErr == noErr )
{
my_assert ( actualSize <= bufferSize,
"\pcgiAEGetParamHTTPMethod: actual param size too big" );
/* terminate the buffer with a null byte */
tempBuffer[actualSize] = nil;
/* compare the buffer with constants to determine the http method used */
stringDiff = strcmp ( tempBuffer, kCGIHTTPMethodPost );
if ( stringDiff == nil )
{
*theMethod = HTTP_post;
}
else
{
stringDiff = strcmp ( tempBuffer, kCGIHTTPMethodGet );
if ( stringDiff == nil )
{
*theMethod = HTTP_get;
}
else
{
stringDiff = strcmp ( tempBuffer, kCGIHTTPMethodGetConditional );
if ( stringDiff == nil )
{
*theMethod = HTTP_getConditional;
}
else
{
*theMethod = HTTP_UNDEFINED;
}
}
}
}
return theErr;
} /* cgiAEGetParamHTTPMethod */
#endif
/*** SEND PARTIAL SUPPORT ***/
#pragma mark -
/* From the WebSTAR 1.2 addendum:
An ACGI has to inform the WebSTAR server that it intends to
return its results in pieces over a period of time, rather than
simply lumping it all into the value returned from the WWWWsdoc
event. WebSTAR examines the results from an ACGI's reply to see
if it matches the string:
<SEND_PARTIAL>
If this 14 character string is matched exactly (case sensitive),
then WebSTAR doesn’t send anything to the client and keeps the
connection open until the timeout period expires or WebSTAR
receives data via the Send Partial event for that con-nection.
Send Partial events received before the <SEND_PARTIAL> response
to the sdoc
event are also a legal way to indicate that server push
functions are to be performed for a given connection.
As long as Send Partial events are received for a given
connection, the timeout timer is restarted and the data is sent
to the client. If the Send Partial event’s “more” parameter is
FALSE, the server closes the connection and assumes that the
ACGI has finished sending data.
To send events back to WebSTAR from a language like C or Pascal,
you must extract and save the “from” Apple event attribute from
the reply event sent to your WWWWsdoc handler. The “from” event
contains the AEAddressDesc used to address the “SPar” events to
WebSTAR.
Here's the general flow of events
1. A WWW client sends an ACGI URL request to WebSTAR.
2. WebSTAR sends a WWWWsdoc event to the ACGI, passing the
connection ID.
3. The ACGI decides it needs to return data in pieces, so it
replies to the sdoc event with the string <SEND_PARTIAL> and
saves the connection ID.
4. WebSTAR sees that the ACGI wants to return partial data, so
it sets a flag indi-cating that the connection should be checked
periodically for timeouts and resets the timer.
5. The ACGI sends a Send Partial event to WebSTAR with the first
chunk of data, the connection ID, and the “more” flag set to
TRUE, indicating more data to come.
6. WebSTAR handles the Send Partial event, finds the requested
connection, and queues up the data for transmission to the
client (allowing the thread owning the connection to schedule
the transmission.) WebSTAR then resets the time-out for the
connection.
Steps 5 and 6 repeat at whatever interval the client decides
until the “more” parameter is false. WebSTAR receives the final
Send Partial event with the “more” flag set to false, sends the
accompanying data, and closes the client connection. */
/* The connection ID is found in theCGIHdl as the 'connection' field.
Connection is used to identify the particular connection on which to send
the data.
The data to be sent is pointed to by theData, which is dataSize bytes long.
If sendMore is true, there is more data to be sent after processing this
event. If it is false, the server will terminate the connection after
sending the data from this event.
theCGIHdl should not be locked when it is passed to this function.
*/
#if kCompileWithCGISendPartial
#pragma segment AppleEvents
p_export
OSErr
CGIAESendPartial ( CGIHdl theCGIHdl, char *theData, long dataSize, Boolean sendMore )
{
OSErr theErr;
DescType descApp;
AEAddressDesc targetAddress;
AppleEvent theAppleEvent;
AppleEvent reply;
short errNum;
DescType returnedType;
long actualSize;
my_assert ( theCGIHdl != NULL, "\pCGIAESendPartial: theCGIHdl is NULL" );
my_assert ( theData != NULL, "\pCGIAESendPartial: theData is NULL" );
/* ••• need to change this to use the process ID from the server */
/* create the application descriptor */
descApp = kAEClassCGI;
theErr = AECreateDesc ( typeApplSignature, &descApp, sizeof(DescType),
&targetAddress );
if ( theErr != noErr )
{
goto EXIT_AESEND;
}
/* create the apple event record */
theErr = AECreateAppleEvent ( kAEClassCGI, kMyAESendPartial, &targetAddress,
kAutoGenerateReturnID, kAnyTransactionID, &theAppleEvent );
if ( theErr != noErr )
{
goto EXIT_AESEND;
}
/* put the data */
theErr = AEPutParamPtr ( &theAppleEvent, kCGIPartialData, typeChar,
theData, dataSize );
if ( theErr != noErr )
{
goto EXIT_AESEND;
}
my_assert ( (HGetState((Handle)theCGIHdl) & kMemoryHandleLockedFlag) == nil,
"\pCGIAESendPartial: theCGIHdl is already locked!" );
HLockHi ( (Handle)theCGIHdl );
/* put the connection id */
theErr = AEPutParamPtr ( &theAppleEvent, kConnectionIDKeyword, typeLongInteger,
&((*theCGIHdl)->connection), sizeof(long) );
if ( theErr != noErr )
{
goto EXIT_AESEND;
}
HUnlock ( (Handle)theCGIHdl );
/* put the more value */
theErr = AEPutParamPtr ( &theAppleEvent, kMoreKeyword, typeBoolean, &sendMore,
sizeof(Boolean) );
if ( theErr != noErr )
{
goto EXIT_AESEND;
}
/* send the apple event */
theErr = AESend ( &theAppleEvent, &reply, kAEWaitReply + kAENeverInteract /*5-14*/,
kAENormalPriority, kAEMyTimeoutInTicks, gAEIdleUPP, NULL );
if ( theErr != noErr )
{
goto EXIT_AESEND;
}
/* extract the error reply */
errNum = noErr;
theErr = AEGetParamPtr ( &reply, keyErrorNumber, typeSMInt, &returnedType, &errNum,
sizeof(errNum), &actualSize );
if ( (theErr != noErr) && (theErr != errAEDescNotFound) )
{
goto EXIT_AESEND;
}
theErr = errNum;
EXIT_AESEND:
AEDisposeDesc ( &targetAddress );
AEDisposeDesc ( &theAppleEvent );
return theErr;
} /* CGIAESendPartial */
#endif /* kCompileWithCGISendPartial */
/** LOGGING **/
#pragma mark -
/* */
p_export
void
CGILogData ( CGIHdl theCGIHdl )
{
#if kCompileWithCGIserver_port || kCompileWithCGISendPartial || kCompileWithCGIFormHandling
char tempStr[256];
#endif
#if kCompileWithCGIFormHandling
long counter;
#endif
LogStringBreakP ( "\p=== CGI PARAMETERS ===" );
#if kCompileWithCGIpath_args
if ( (*theCGIHdl)->path_args != NULL )
{
LogString ( "path_args:" );
LogStringBreak ( (*theCGIHdl)->path_args );
}
#endif
#if kCompileWithCGIhttp_search_args
if ( (*theCGIHdl)->http_search_args != NULL )
{
LogString ( "http_search_args:" );
LogStringBreak ( (*theCGIHdl)->http_search_args );
}
#endif
#if kCompileWithCGIusername
LogString ( "username:" );
LogStringBreak ( (*theCGIHdl)->username );
#endif
#if kCompileWithCGIpassword
if ( (*theCGIHdl)->password != NULL )
{
LogString ( "password:" );
LogStringBreak ( (*theCGIHdl)->password );
}
#endif
#if kCompileWithCGIfrom_user
if ( (*theCGIHdl)->from_user != NULL )
{
LogString ( "from_user:" );
LogStringBreak ( (*theCGIHdl)->from_user );
}
#endif
#if kCompileWithCGIclient_address
if ( (*theCGIHdl)->client_address != NULL )
{
LogString ( "client_address:" );
LogStringBreak ( (*theCGIHdl)->client_address );
}
#endif
#if kCompileWithCGIpost_args
if ( (*theCGIHdl)->post_args != NULL )
{
LogString ( "post_args:" );
LogStringBreak ( (*theCGIHdl)->post_args );
}
#endif
#if kCompileWithCGImethod
LogString ( "method:" );
switch ( (*theCGIHdl)->method )
{
case HTTP_get :
LogStringBreak ( kCGIHTTPMethodGet );
break;
case HTTP_post :
LogStringBreak ( kCGIHTTPMethodPost );
break;
case HTTP_getConditional :
LogStringBreak ( kCGIHTTPMethodGetConditional );
break;
default :
LogStringBreak ( "<undefined>" );
break;
}
#endif
#if kCompileWithCGIserver_name
if ( (*theCGIHdl)->server_name != NULL )
{
LogString ( "server_name:" );
LogStringBreak ( (*theCGIHdl)->server_name );
}
#endif
#if kCompileWithCGIserver_port
LogString ( "server_port:" );
sprintf ( tempStr, "%d", (*theCGIHdl)->server_port );
LogStringBreak ( tempStr );
#endif
#if kCompileWithCGIscript_name
if ( (*theCGIHdl)->script_name != NULL )
{
LogString ( "script_name:" );
LogStringBreak ( (*theCGIHdl)->script_name );
}
#endif
#if kCompileWithCGIcontent_type
if ( (*theCGIHdl)->content_type != NULL )
{
LogString ( "content_type:" );
LogStringBreak ( (*theCGIHdl)->content_type );
}
#endif
#if kCompileWithCGIreferer
if ( (*theCGIHdl)->referer != NULL )
{
LogString ( "referer:" );
LogStringBreak ( (*theCGIHdl)->referer );
}
#endif
#if kCompileWithCGIuser_agent
if ( (*theCGIHdl)->user_agent != NULL )
{
LogString ( "user_agent:" );
LogStringBreak ( (*theCGIHdl)->user_agent );
}
#endif
#if kCompileWithCGIActionSupport
LogString ( "action:" );
LogStringBreak ( (*theCGIHdl)->action );
if ( (*theCGIHdl)->action_path != NULL )
{
LogString ( "action_path:" );
LogStringBreak ( (*theCGIHdl)->action_path );
}
#endif
#if kCompileWithCGIclient_ip
LogString ( "client_ip:" );
LogStringBreak ( (*theCGIHdl)->client_ip );
#endif
#if kCompileWithCGIfull_request
if ( (*theCGIHdl)->full_request != NULL )
{
LogString ( "full_request:" );
LogStringBreak ( (*theCGIHdl)->full_request );
}
#endif
#if kCompileWithCGISendPartial
LogString ( "connection:" );
sprintf ( tempStr, "%d", (*theCGIHdl)->connection );
LogStringBreak ( tempStr );
#endif
#if kCompileWithCGIFormHandling
LogString ( "totalFields:" );
sprintf ( tempStr, "%d", (*theCGIHdl)->totalFields );
LogStringBreak ( tempStr );
if ( (*theCGIHdl)->totalFields > nil )
{
LogStringBreak ( "formFields:" );
for ( counter = 0; counter < (*theCGIHdl)->totalFields; counter++ )
{
LogStringP ( "\p\t" ); /* put a tab character at the begining */
LogStringAndSeparator ( (((*theCGIHdl)->formFields)[counter]).name, '\t' );
LogStringBreak ( (((*theCGIHdl)->formFields)[counter]).value );
}
}
#endif
LogStringBreakP ( "\p=== end cgi parameters ===" );
} /* CGILogData */
#endif /* kCompileWithCGICode */
/*** EOF ***/